#include "nuc970.h"
#include "nuc970_i2c.h"
#include "nuc970_lcd.h"
#include "nuc970_uart.h"
#include "nuc970_spi.h"

#if defined(__NUC972DF62Y)
#elif defined(__NUC976DK61Y)
#endif

void MFP_GPIOInit()
{
    outpw(REG_SYS_APBIPRST0, inpw(REG_SYS_APBIPRST0) | SYS_IPRST_GPIO);
    outpw(REG_SYS_APBIPRST0, inpw(REG_SYS_APBIPRST0) & (~SYS_IPRST_GPIO));
    outpw(REG_CLK_PCLKEN0, inpw(REG_CLK_PCLKEN0) | SYS_CLKEN_GPIO); //Enable GPIO engin clock.
}

void MFP_I2CInit(I2C_TypeDef *i2c)
{
    if (i2c == I2C0) {
        outpw(REG_SYS_APBIPRST1, inpw(REG_SYS_APBIPRST1) | SYS_IPRST_I2C0);
        outpw(REG_SYS_APBIPRST1, inpw(REG_SYS_APBIPRST1) & (~SYS_IPRST_I2C0));

        /* Configure multi function pins to I2C0 */
        outpw(REG_SYS_GPG_MFPL, (inpw(REG_SYS_GPG_MFPL) & ~0xFF) | 0x88);

        /* I2C clock pin enable schmitt trigger */
        outpw(REG_GPIOG_ISEN, (inpw(REG_GPIOG_ISEN) | 0x3));

        outpw(REG_CLK_PCLKEN1, inpw(REG_CLK_PCLKEN1) | SYS_CLKEN_I2C0);
    } else if (i2c == I2C1) {
        outpw(REG_SYS_APBIPRST1, inpw(REG_SYS_APBIPRST1) | SYS_IPRST_I2C1);
        outpw(REG_SYS_APBIPRST1, inpw(REG_SYS_APBIPRST1) & (~SYS_IPRST_I2C1));

        /* Configure multi function pins to I2C1 */
        outpw(REG_SYS_GPG_MFPL, (inpw(REG_SYS_GPG_MFPL) & ~0xFF00) | 0x8800);
        /* I2C clock pin enable schmitt trigger */
        outpw(REG_GPIOG_ISEN, (inpw(REG_GPIOG_ISEN) | 0x300));

        // outpw(REG_SYS_GPH_MFPL, (inpw(REG_SYS_GPH_MFPL) & ~0xFF00) | 0x8800);
        // /* I2C clock pin enable schmitt trigger */
        // outpw(REG_GPIOH_ISEN, (inpw(REG_GPIOH_ISEN) | 0x300));

        // outpw(REG_SYS_GPI_MFPL, (inpw(REG_SYS_GPI_MFPL) & ~0xFF000) | 0x88000);
        // /* I2C clock pin enable schmitt trigger */
        // outpw(REG_GPIOI_ISEN, (inpw(REG_GPIOI_ISEN) | 0x3000));

        outpw(REG_CLK_PCLKEN1, inpw(REG_CLK_PCLKEN1) | SYS_CLKEN_I2C1);
    }
}
void MFP_I2CDeInit(I2C_TypeDef *i2c)
{
    if (i2c == I2C0) {
        outpw(REG_SYS_APBIPRST1, inpw(REG_SYS_APBIPRST1) | SYS_IPRST_I2C0);
        outpw(REG_SYS_APBIPRST1, inpw(REG_SYS_APBIPRST1) & (~SYS_IPRST_I2C0));
        
        outpw(REG_SYS_GPG_MFPL, (inpw(REG_SYS_GPG_MFPL) & ~0xFF));
        
        outpw(REG_CLK_PCLKEN1, inpw(REG_CLK_PCLKEN1) & (~SYS_CLKEN_I2C0));
    } else if (i2c == I2C1) {
        outpw(REG_SYS_APBIPRST1, inpw(REG_SYS_APBIPRST1) | SYS_IPRST_I2C1);
        outpw(REG_SYS_APBIPRST1, inpw(REG_SYS_APBIPRST1) & (~SYS_IPRST_I2C1));

        outpw(REG_SYS_GPG_MFPL, (inpw(REG_SYS_GPG_MFPL) & ~0xFF00));
        // outpw(REG_SYS_GPH_MFPL, (inpw(REG_SYS_GPH_MFPL) & ~0xFF00));
        // outpw(REG_SYS_GPI_MFPL, (inpw(REG_SYS_GPI_MFPL) & ~0xFF000));

        outpw(REG_CLK_PCLKEN1, inpw(REG_CLK_PCLKEN1) & (~SYS_CLKEN_I2C1));
    }
}

void MFP_LCMInit(void)
{
    outpw(REG_SYS_AHBIPRST, inpw(REG_SYS_AHBIPRST) | SYS_IPRST_LCD);
    outpw(REG_SYS_AHBIPRST, inpw(REG_SYS_AHBIPRST) & (~SYS_IPRST_LCD));

    // Configure multi-function pin for LCD interface
#if defined(__NUC972DF62Y)
    // GPG6 (CLK), GPG7 (HSYNC)
    outpw(REG_SYS_GPG_MFPL, (inpw(REG_SYS_GPG_MFPL) & ~0xFF000000) | 0x22000000);
    // GPG8 (VSYNC), GPG9 (DEN)
    outpw(REG_SYS_GPG_MFPH, (inpw(REG_SYS_GPG_MFPH) & ~0xFF) | 0x22);

    // DATA pin
    // GPA0 ~ GPA7 (DATA0~7)
    outpw(REG_SYS_GPA_MFPL, 0x22222222);
    // GPA8 ~ GPA15 (DATA8~15)
    outpw(REG_SYS_GPA_MFPH, 0x22222222);

    // GPD8~D15 (DATA16~23)
    outpw(REG_SYS_GPD_MFPH, 0x22222222);
#elif defined(__NUC976DK61Y)
    // GPG6 (CLK), GPG7 (HSYNC)
    outpw(REG_SYS_GPG_MFPL, (inpw(REG_SYS_GPG_MFPL) & ~0xFF000000) | 0x22000000);
    // GPG8 (VSYNC)
    outpw(REG_SYS_GPG_MFPH, (inpw(REG_SYS_GPG_MFPH) & ~0xF) | 0x2);

    // DATA pin
    // GPA0 ~ GPA7 (DATA0~7)
    outpw(REG_SYS_GPA_MFPL, 0x22222222);
    // GPA8 ~ GPA15 (DATA8~15)
    outpw(REG_SYS_GPA_MFPH, 0x22222222);
#endif
#if defined (USE_E50A2V1) | defined (USE_E50A2V1_RGB565)
    // LCD clock is selected from UPLL and divide to 20MHz
    outpw(REG_CLK_DIVCTL1, (inpw(REG_CLK_DIVCTL1) & ~0xFF1F) | 0xE18);
#elif defined (USE_TM043)
    // LCD clock is selected from UPLL and divide to 9MHz
    outpw(REG_CLK_DIVCTL1, (inpw(REG_CLK_DIVCTL1) & ~0xFF1F) | 0x1818);
#endif

    // enable lcd engine clock
    outpw(REG_CLK_HCLKEN, inpw(REG_CLK_HCLKEN) | SYS_CLKEN_LCD);
}

void MFP_LCMDeInit()
{
    // disable lcd engine clock
    outpw(REG_CLK_HCLKEN, inpw(REG_CLK_HCLKEN) & (~SYS_CLKEN_LCD));

    outpw(REG_SYS_AHBIPRST, inpw(REG_SYS_AHBIPRST) | SYS_IPRST_LCD);
    outpw(REG_SYS_AHBIPRST, inpw(REG_SYS_AHBIPRST) & (~SYS_IPRST_LCD));
}

void MFP_GE2DInit()
{
    outpw(REG_SYS_AHBIPRST, inpw(REG_SYS_AHBIPRST) | SYS_IPRST_GE2D);
    outpw(REG_SYS_AHBIPRST, inpw(REG_SYS_AHBIPRST) & (~SYS_IPRST_GE2D));

    outpw(REG_GE2D_INTSTS, 0); // clear interrupt
    outpw(REG_GE2D_CTL, 0); // disable interrupt

    // enable ge2d engine clock
    outpw(REG_CLK_HCLKEN, inpw(REG_CLK_HCLKEN) | SYS_CLKEN_GE2D);
}

void MFP_GE2DDeInit()
{
    outpw(REG_GE2D_CTL, 0); // disable interrupt
    outpw(REG_GE2D_INTSTS, 0); // clear interrupt
    // disable ge2d engine clock
    outpw(REG_CLK_HCLKEN, inpw(REG_CLK_HCLKEN) & (~SYS_CLKEN_GE2D));

    outpw(REG_SYS_AHBIPRST, inpw(REG_SYS_AHBIPRST) | SYS_IPRST_GE2D);
    outpw(REG_SYS_AHBIPRST, inpw(REG_SYS_AHBIPRST) & (~SYS_IPRST_GE2D));
}

void MFP_UARTInit(UART_TypeDef *uart)
{
    if (uart == UART1) {
        outpw(REG_SYS_APBIPRST0, inpw(REG_SYS_APBIPRST0) | SYS_IPRST_UART1);
        outpw(REG_SYS_APBIPRST0, inpw(REG_SYS_APBIPRST0) & (~SYS_IPRST_UART1));

#if defined(__NUC972DF62Y)
        // GPE2 (TXD1), GPE3 (RXD1)
        outpw(REG_SYS_GPE_MFPL, (inpw(REG_SYS_GPE_MFPL) & ~0x0000FF00) | 0x00009900);
#elif defined(__NUC976DK61Y)
        // GPI5 (TXD1), GPI6 (RXD1)
        outpw(REG_SYS_GPI_MFPL, (inpw(REG_SYS_GPI_MFPL) & ~0x0FF00000) | 0x09900000);
#endif
        // enable uart1 clock
        outpw(REG_CLK_PCLKEN0, inpw(REG_CLK_PCLKEN0) | SYS_CLKEN_UART1);
    } else if (uart == UART4) {
        outpw(REG_SYS_APBIPRST0, inpw(REG_SYS_APBIPRST0) | SYS_IPRST_UART4);
        outpw(REG_SYS_APBIPRST0, inpw(REG_SYS_APBIPRST0) & (~SYS_IPRST_UART4));

#if defined(__NUC972DF62Y)
        // GPI9 (TXD4), GPI10 (RXD4)
        outpw(REG_SYS_GPI_MFPH, (inpw(REG_SYS_GPI_MFPH) & ~0x00000FF0) | 0x00000990);
#elif defined(__NUC976DK61Y)
        // GPI9 (TXD4), GPI10 (RXD4)
        outpw(REG_SYS_GPI_MFPH, (inpw(REG_SYS_GPI_MFPH) & ~0x00000FF0) | 0x00000990);
#endif
        // enable uart4 clock
        outpw(REG_CLK_PCLKEN0, inpw(REG_CLK_PCLKEN0) | SYS_CLKEN_UART4);
    } else if (uart == UART6) {
        outpw(REG_SYS_APBIPRST0, inpw(REG_SYS_APBIPRST0) | SYS_IPRST_UART6);
        outpw(REG_SYS_APBIPRST0, inpw(REG_SYS_APBIPRST0) & (~SYS_IPRST_UART6));

#if defined(__NUC972DF62Y)
        outpw(REG_SYS_GPG_MFPH, (inpw(REG_SYS_GPG_MFPH) & ~0x000FF000) | 0x00099000);
#elif defined(__NUC976DK61Y)
        // GPG11 (TXD6), GPG12 (RXD6)
        outpw(REG_SYS_GPG_MFPH, (inpw(REG_SYS_GPI_MFPH) & ~0x000FF000) | 0x00099000);
#endif
        // enable uart6 clock
        outpw(REG_CLK_PCLKEN0, inpw(REG_CLK_PCLKEN0) | SYS_CLKEN_UART6);
    }
}

void MFP_UARTDeInit(UART_TypeDef *uart)
{
    if (uart == UART1) {
        outpw(REG_SYS_APBIPRST0, inpw(REG_SYS_APBIPRST0) | SYS_IPRST_UART1);
        outpw(REG_SYS_APBIPRST0, inpw(REG_SYS_APBIPRST0) & (~SYS_IPRST_UART1));

        // disable uart1 clock
        outpw(REG_CLK_PCLKEN0, inpw(REG_CLK_PCLKEN0) & (~SYS_CLKEN_UART1));
    } else if (uart == UART4) {
        outpw(REG_SYS_APBIPRST0, inpw(REG_SYS_APBIPRST0) | SYS_IPRST_UART4);
        outpw(REG_SYS_APBIPRST0, inpw(REG_SYS_APBIPRST0) & (~SYS_IPRST_UART4));

        // disable uart4 clock
        outpw(REG_CLK_PCLKEN0, inpw(REG_CLK_PCLKEN0) & (~SYS_CLKEN_UART4));
    } else if (uart == UART6) {
        outpw(REG_SYS_APBIPRST0, inpw(REG_SYS_APBIPRST0) | SYS_IPRST_UART6);
        outpw(REG_SYS_APBIPRST0, inpw(REG_SYS_APBIPRST0) & (~SYS_IPRST_UART6));

        // disable uart6 clock
        outpw(REG_CLK_PCLKEN0, inpw(REG_CLK_PCLKEN0) & (~SYS_CLKEN_UART6));
    }
}

void MFP_USBHInit()
{
    outpw(REG_SYS_AHBIPRST, inpw(REG_SYS_AHBIPRST) | SYS_IPRST_USBH);
    outpw(REG_SYS_AHBIPRST, inpw(REG_SYS_AHBIPRST) & (~SYS_IPRST_USBH));
    outpw(REG_CLK_HCLKEN, inpw(REG_CLK_HCLKEN) | SYS_CLKEN_USBH); //Enable USBH engin clock.
#if defined(__NUC972DF62Y)
    // GPE14 (USBH_PPWR0), GPE15 (USBH_PPWR1)
    outpw(REG_SYS_GPE_MFPH, (inpw(REG_SYS_GPE_MFPH) & ~0xFF000000) | 0x77000000);
#elif defined(__NUC976DK61Y)
#endif
}

void MFP_USBHDeInit()
{
    outpw(REG_SYS_AHBIPRST, inpw(REG_SYS_AHBIPRST) | SYS_IPRST_USBH);
    outpw(REG_SYS_AHBIPRST, inpw(REG_SYS_AHBIPRST) & (~SYS_IPRST_USBH));
    outpw(REG_CLK_HCLKEN, inpw(REG_CLK_HCLKEN) & (~SYS_CLKEN_USBH)); //Disable USBH engin clock.
}

void MFP_USBDInit()
{
    outpw(REG_SYS_AHBIPRST, inpw(REG_SYS_AHBIPRST) | SYS_IPRST_USBD);
    outpw(REG_SYS_AHBIPRST, inpw(REG_SYS_AHBIPRST) & (~SYS_IPRST_USBD));
    outpw(REG_CLK_HCLKEN, inpw(REG_CLK_HCLKEN) | SYS_CLKEN_USBD); //Enable USBD engin clock.
}

void MFP_USBDDeInit()
{
    outpw(REG_SYS_AHBIPRST, inpw(REG_SYS_AHBIPRST) | SYS_IPRST_USBD);
    outpw(REG_SYS_AHBIPRST, inpw(REG_SYS_AHBIPRST) & (~SYS_IPRST_USBD));
    outpw(REG_CLK_HCLKEN, inpw(REG_CLK_HCLKEN) & (~SYS_CLKEN_USBD)); //Disable USBD engin clock.
}

void MFP_ETH0Init()
{
    outpw(REG_SYS_AHBIPRST, inpw(REG_SYS_AHBIPRST) | SYS_IPRST_EMAC0);
    outpw(REG_SYS_AHBIPRST, inpw(REG_SYS_AHBIPRST) & (~SYS_IPRST_EMAC0));
    outpw(REG_CLK_HCLKEN, inpw(REG_CLK_HCLKEN) | SYS_CLKEN_EMAC0); //Enable EMAC0 engin clock.
    
    outpw(REG_CLK_DIVCTL8, (inpw(REG_CLK_DIVCTL8) & ~0xFF) | 0xA0);     // MDC clk divider

    // GPF0~9
    outpw(REG_SYS_GPF_MFPL, 0x11111111);
    outpw(REG_SYS_GPF_MFPH, (inpw(REG_SYS_GPF_MFPH) & ~0xFF) | 0x11);

    // Reset MAC
    outpw(REG_EMAC0_MCMDR, 0x1000000);
}

void MFP_ETH0DeInit()
{
    outpw(REG_SYS_AHBIPRST, inpw(REG_SYS_AHBIPRST) | SYS_IPRST_EMAC0);
    outpw(REG_SYS_AHBIPRST, inpw(REG_SYS_AHBIPRST) & (~SYS_IPRST_EMAC0));
    outpw(REG_CLK_HCLKEN, inpw(REG_CLK_HCLKEN) & (~SYS_CLKEN_EMAC0)); //Disable EMAC0 engin clock.
}

void MFP_SPIInit(SPI_TypeDef *spi)
{
    if (spi == SPI0) {
        outpw(REG_SYS_APBIPRST1, inpw(REG_SYS_APBIPRST1) | SYS_IPRST_SPI0);
        outpw(REG_SYS_APBIPRST1, inpw(REG_SYS_APBIPRST1) & (~SYS_IPRST_SPI0));

        outpw(REG_SYS_GPB_MFPL, (inpw(REG_SYS_GPB_MFPL)& ~0xFF000000) | 0xBB000000);
        outpw(REG_SYS_GPB_MFPH, (inpw(REG_SYS_GPB_MFPH)& ~0x000000FF) | 0x000000BB);

        outpw(REG_CLK_PCLKEN1, inpw(REG_CLK_PCLKEN1) | SYS_CLKEN_SPI0);      // Enable SPI0 engin clock.
    } else if (spi == SPI1) {
        outpw(REG_SYS_APBIPRST1, inpw(REG_SYS_APBIPRST1) | SYS_IPRST_SPI1);
        outpw(REG_SYS_APBIPRST1, inpw(REG_SYS_APBIPRST1) & (~SYS_IPRST_SPI1));

        outpw(REG_CLK_PCLKEN1, inpw(REG_CLK_PCLKEN1) | SYS_CLKEN_SPI1);      // Enable SPI1 engin clock.
    }
}

void MFP_SPIDeInit(SPI_TypeDef *spi)
{
    if (spi == SPI0) {
        outpw(REG_SYS_APBIPRST1, inpw(REG_SYS_APBIPRST1) | SYS_IPRST_SPI0);
        outpw(REG_SYS_APBIPRST1, inpw(REG_SYS_APBIPRST1) & (~SYS_IPRST_SPI0));

        outpw(REG_CLK_PCLKEN1, inpw(REG_CLK_PCLKEN1) & (~SYS_CLKEN_SPI0));      // Disable SPI0 engin clock.
    } else if (spi == SPI1) {
        outpw(REG_SYS_APBIPRST1, inpw(REG_SYS_APBIPRST1) | SYS_IPRST_SPI1);
        outpw(REG_SYS_APBIPRST1, inpw(REG_SYS_APBIPRST1) & (~SYS_IPRST_SPI1));

        outpw(REG_CLK_PCLKEN1, inpw(REG_CLK_PCLKEN1) & (~SYS_CLKEN_SPI1));      // Disable SPI1 engin clock.
    }
}
